/* -*- mode: c++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- */

#ifndef MAILSERV_UTILITY_H
#define MAILSERV_UTILITY_H

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>

#include <string>
#include <vector>

#include <strhelper.h>

/* 时间精度需要 64 位正整数
 */
#ifndef DECL_UINT64_TYPE
#define DECL_UINT64_TYPE 1
typedef unsigned long long Uint64;
#endif

struct date_s {
    unsigned short year;
    unsigned char  month;
    unsigned char  day;
    unsigned char  hour;
    unsigned char  minute;
    unsigned char  second;

    date_s()
    {
    }

    date_s(const date_s& o) {
        year   = o.year;
        month  = o.month;
        day    = o.day;
        hour   = o.hour;
        minute = o.minute;
        second = o.second;
    }

    bool operator== (const date_s& other) const {
        return
            year   == other.year   &&
            month  == other.month  &&
            day    == other.day    &&
            hour   == other.hour   &&
            minute == other.minute &&
            second == other.second;
    }

    bool month_less(const date_s& other) const {
        if (year < other.year)
            return true;
        else if (year > other.year)
            return false;

        if (month < other.month)
            return true;

        return false;
    }

    bool month_equal(const date_s& other) const {
        return year == other.year && month == other.month;
    }

    bool day_less(const date_s& other) const {
        if (year < other.year)
            return true;
        else if (year > other.year)
            return false;

        if (month < other.month)
            return true;
        else if (month > other.month)
            return false;

        return (day < other.day);
    }

    bool day_equal(const date_s& other) const {
        return
            year   == other.year  &&
            month  == other.month &&
            day    == other.day;
    }

    bool time_less(const date_s& other) const {
        if (hour < other.hour)
            return true;
        else if (hour > other.hour)
            return false;

        if (minute < other.minute)
            return true;
        else if (minute > other.minute)
            return false;

        return (second < other.second);
    }

    bool time_equal(const date_s& other) const {
        return
            hour   == other.hour   &&
            minute == other.minute &&
            second == other.second;
    }

    bool operator< (const date_s& other) const {
        if (year < other.year)
            return true;
        else if (year > other.year)
            return false;

        if (month < other.month)
            return true;
        else if (month > other.month)
            return false;

        if (day < other.day)
            return true;
        else if (day > other.day)
            return false;

        if (hour < other.hour)
            return true;
        else if (hour > other.hour)
            return false;

        if (minute < other.minute)
            return true;
        else if (minute > other.minute)
            return false;

        return (second < other.second);
    }
};

typedef struct date_s date_t;

extern Uint64 get_ticks();

extern void sleep_us(int us);

extern void get_date(date_t *d);

extern void get_date_prev_ndays(date_t *d, int n);

// Returns true if path is a directory and false otherwise.
extern bool is_dir(const char* path);

extern bool is_reg_file(const char *path);

extern bool create_dir(const char *dir);

extern void get_curr_time_fmt(std::string& result);

extern void get_curr_time_spec(std::string&  result,
                               const char   *fmt);

extern void get_curr_time(std::string& result);

template<typename Cont>
int remove_elem(Cont& cont, const typename Cont::value_type& elem)
{
    typename Cont::iterator
        beg = cont.begin(),
        end = cont.end();
    int cnt = 0;
    while (beg != end) {
        if (*beg == elem) {
            cont.erase(beg++);
            ++cnt;
        }
        else
            ++beg;
    }
    return cnt;
}

template<typename Cont, typename Pred>
int remove_elem_pred(Cont& cont, Pred pred)
{
    typename Cont::iterator
        beg = cont.begin(),
        end = cont.end();
    int cnt = 0;
    while (beg != end) {
        if (pred(*beg)) {
            cont.erase(beg++);
            ++cnt;
        }
        else
            ++beg;
    }
    return cnt;
}

template<typename Cont, typename Pred>
typename Cont::value_type
dequeue_pred(Cont&                     cont,
             Pred                      pred,
             typename Cont::value_type def)
{
    typename Cont::iterator
        beg = cont.begin(),
        end = cont.end();
    while (beg != end) {
        typename Cont::value_type r = *beg;
        if (pred(r)) {
            cont.erase(beg);
            return r;
        }
        else
            ++beg;
    }
    return def;
}

template<typename Elem, typename Cont>
bool elem_in_set(const Elem& elem,
                 const Cont& cont)
{
    if (!cont.empty()) {
        typename Cont::const_iterator cur = cont.begin();
        typename Cont::const_iterator end = cont.end();

        while (cur != end) {
            if (*cur == elem)
                return true;

            ++cur;
        }
    }

    return false;
}

enum {
    DATE_OP_LT,

    DATE_OP_GT,

    DATE_OP_LE,

    DATE_OP_GE,

    DATE_OP_EQ,

    DATE_OP_UNKNOW,
};

extern bool all_dig_p(const char *s);

extern int str2int(const char *s, int *res, int len);

extern int parse_time_op(const char *s, date_t& d);

typedef std::vector<std::string> Strings;

typedef std::vector<int> Ints;

extern void *util_mem_dup(const void *ptr, int len);

#endif
